/**
 * Static class UserManager. Handles functionality access
 * 
 * @author Maxime Ollagnier
 */

UserManager = function() {
};

/** Currently logged user */
UserManager.user = undefined;

/** Available role groups */
UserManager.groups = undefined;

/** Available roles */
UserManager.roles = undefined;

/** Referrer types */
UserManager.TYPE_CREDITOR = 'creditor';
UserManager.TYPE_ENTITY = 'not creditor';
UserManager.TYPE_BOTH = 'both';

/** User types */
UserManager.USER_TYPE_VALUES = {};
UserManager.USER_TYPE_VALUES['CREDITOR'] = 10;
UserManager.USER_TYPE_VALUES['ORGENTITY'] = 20;
UserManager.USER_TYPE_VALUES['BACKOFFICE'] = 30;

/**
 * Initializes the currently logged user
 */
UserManager.init = function(callback) {
	AjaxManager.getJSON('getUser', {}, function(result) {
    	if (result.success) {
			UserManager.user = result.user;
			UserManager.checkPasswordExpiration(UserManager.user, function() {
				AjaxManager.getJSON('getGroups', {}, function(result) {
			    	if (result.success) {
						UserManager.groups = result.groups;
						AjaxManager.getJSON('getRoles', {}, function(result) {
					    	if (result.success) {
								UserManager.roles = result.roles;
								Util.getFunction(callback)();
							}
						});
					}
				});
			});
		}
	});
};


/**
 * Check if there is a password expiration and if it has expired, if so display the change password popup
 */
UserManager.checkPasswordExpiration = function(user, callback){
	//if user exists, password expiration exists and has expired
	if (Util.checkObject(user) && 
		(Util.check(user.passwordExpiration) && 
		Util.checkNumber(user.passwordExpiration) && 
		user.passwordExpiration < moment().valueOf()) ||
		(Util.check(user.passwordChangeRequired) &&
		Util.checkBoolTrue(user.passwordChangeRequired))){
		
		
		var passwordChangeModule = new PasswordChangeModule();
		NavigationManager.getJQPage().append('<h4>' + I18n.get('change.password.message') + '</h4>');
		passwordChangeModule.buildJQ();
		passwordChangeModule.getJQ().find('.InputTextModule').addClass('span7 connexion-change-password');
		NavigationManager.getJQPage().append(passwordChangeModule.getJQ());
		
		//button
		var buttonRow = $('<div></div>');
		NavigationManager.getJQPage().append(buttonRow);
		var buttonChangePassword = $('<div class="btn search">' + I18n.get('change.password.button') + '</div>');
		buttonRow.append(buttonChangePassword);
		buttonChangePassword.click(function() {
			passwordChangeModule.submitChange(function(success, userMessageCode) {
				if (success) {
					PopupModule.getInstance().show({
						'title' : I18n.get('password.changed'),
						'content' : I18n.get('password.changed.desc'),
						'button0' : { 'text' : 'OK', 'callback': function() { 
							Util.getFunction(callback)();
						} }
					});
				}
			});
		});
		
	} else {
		//callback
		Util.getFunction(callback)();
	}
};

/**
 * Returns true if the given referrer is a creditor, false otherwise
 * @param referrer
 */
UserManager.isCreditor = function(referrer){
	return Util.checkObject(referrer) && referrer.type === UserManager.TYPE_CREDITOR;
};

/**
 * Returns the userType of the referrer
 * @param referrer
 */
UserManager.getUserType = function(referrer) {
	var userType = EnumManager.UserType.CREDITOR;
	if (Util.checkObject(referrer)) {
		if (referrer.type != UserManager.TYPE_CREDITOR) {
			userType = EnumManager.UserType.ORGENTITY;
		}
		if (!Util.check(referrer.parentId)) {
			userType = EnumManager.UserType.BACKOFFICE;
		}
	}
	return userType;
};

/**
 * Returns the map of groups with the given user type
 */
UserManager.getGroups = function(userType) {
	var groupMap = {};
	$.each(UserManager.groups, function(groupId, group) {
		if (!Util.check(userType) || UserManager.USER_TYPE_VALUES[group.userType] <= UserManager.USER_TYPE_VALUES[userType]) {
			groupMap[groupId] = group;
		}
	});
	return groupMap;
};

/**
 * Returns true if every given role name is contained in the currently logged user roles
 */
UserManager.hasRoles = function(roleNames) {
	for (var i = 0; i < roleNames.length; i++) {
		if (!UserManager.hasRole(roleNames[i])) {
			return false;
		}
	}
	return true;
};

/**
 * Returns true if the given role name is contained in the currently logged user roles
 */
UserManager.hasRole = function(roleName) {
	var contains = false;
	for (var i = 0; i < UserManager.user.groups.length && !contains; i++) {
		$.each(UserManager.user.groups[i].roles, function(name, role) {
			if (role.name == roleName) {
				contains = true;
				return true;
			}
		});
	}
	return contains;
};

/**
 * Returns the merged list of roles for the given map of groups of list of groups ids
 */
UserManager.getRoles = function(userTypeOrGroupMapOrGroupIds) {
	if (!Util.check(userTypeOrGroupMapOrGroupIds)) {
		return UserManager.roles;
	}
	if (Util.checkString(userTypeOrGroupMapOrGroupIds)) {
		var roles = {};
		$.each(UserManager.roles, function(name, role) {
			if (UserManager.USER_TYPE_VALUES[role.userType] <= UserManager.USER_TYPE_VALUES[userTypeOrGroupMapOrGroupIds]) {
				roles[name] = role;
			}
		});
		return roles;
	}
	var groupMap = undefined;
	if (Util.checkArray(userTypeOrGroupMapOrGroupIds)) {
		groupMap = {};
		for (var i = 0; i < userTypeOrGroupMapOrGroupIds.length; i++) {
			groupMap[userTypeOrGroupMapOrGroupIds[i]] = UserManager.groups[userTypeOrGroupMapOrGroupIds[i]];
		}
	}
	else if (Util.checkObject(userTypeOrGroupMapOrGroupIds)) {
		groupMap = userTypeOrGroupMapOrGroupIds;
	}
	var roles = {};
	if (Util.check(groupMap)) {
		$.each(groupMap, function(id, group) {
			$.each(group.roles, function(name, role) {
				var alreadyAdded = false;
				$.each(roles, function(addedRoleName, addedRole) {
					alreadyAdded = alreadyAdded || addedRole.name == role.name;
				});
				if (!alreadyAdded) {
					roles[name] = role;
				}
			});
		});
	}
	return Object.sortByValue(roles, function(role1, role2) {
		return role1.name.compare(role2.name);
	});
};

/**
 * Returns the referrer with the given ID if accessible
 * 
 * @param referrerId the id of the referrer to get
 * @param parentReferrer is used by this method for recursion (optional for usage)
 */
UserManager.getReferrer = function(referrerId, parentReferrer) {
	if (!Util.checkObject(parentReferrer)) {
		parentReferrer = UserManager.user.referrer;
	}
	if (parentReferrer.id == referrerId) {
		return parentReferrer;
	}
	if (parentReferrer.type == UserManager.TYPE_CREDITOR) {
		return undefined;
	}
	for (var i = 0; i < parentReferrer.children.length; i++) {
		var foundReferrer = UserManager.getReferrer(referrerId, parentReferrer.children[i]);
		if (Util.checkObject(foundReferrer)) {
			return foundReferrer;
		}
	}
	return undefined;
};

/**
 * Sets the referrer with the given ID if possible
 * 
 * @param referrer the new referrer to be set
 * @param parentReferrer is used by this method for recursion (optional for usage)
 */
UserManager.setReferrer = function(referrer, parentReferrer) {
	if (UserManager.user.referrer.id == referrer.id) {
		UserManager.user.referrer = referrer;
		return true;
	}
	if (!Util.checkObject(parentReferrer)) {
		parentReferrer = UserManager.user.referrer;
	}
	var foundAndSet = false;
	if (parentReferrer.type != UserManager.TYPE_CREDITOR) {
		for (var i = 0; i < parentReferrer.children.length && !foundAndSet; i++) {
			if (parentReferrer.children[i].id == referrer.id && (
				(parentReferrer.children[i].type != UserManager.TYPE_CREDITOR && referrer.type != UserManager.TYPE_CREDITOR) ||
				(parentReferrer.children[i].type == UserManager.TYPE_CREDITOR && referrer.type == UserManager.TYPE_CREDITOR))) {
				//child has been found
				if (parentReferrer.children[i].parentId == referrer.parentId){
					//replace it if parent didn't change
					parentReferrer.children[i] = referrer;
					//we don't need to continue, referrer is replaced, it's done -> return true
					return true;
				} else {
					//remove referrer if parent has changed
					parentReferrer.children.splice(i,1);
					//return false lead to continue the search until the end
					//if referrer remains not found, it will be added in the proper branch
					return false;
				}
			} else if (parentReferrer.children[i].type != UserManager.TYPE_CREDITOR) {
				foundAndSet = UserManager.setReferrer(referrer, parentReferrer.children[i]);
			}
		}
		//if referrer remains not found, and it is the parent, add it as children
		if (!foundAndSet && referrer.parentId == parentReferrer.id) {
			parentReferrer.children.push(referrer);
			//if referrer is pushed, it may be removed from an other branch, so continue the deep search by returning true
			return false;
		}
	}
	return false;
};

/**
 * Deletes the referrer with the given ID if possible
 * 
 * @param referrerId the ID of the referrer to delete
 * @param parentReferrer is used by this method for recursion (optional for usage)
 */
UserManager.deleteReferrer = function(referrerId, parentReferrer) {
	if (UserManager.user.referrer.id == referrerId) {
		throw 'ERROR - User referrer should NOT be deleted !!!';
	}
	if (!Util.checkObject(parentReferrer)) {
		parentReferrer = UserManager.user.referrer;
	}
	var foundAndDeleted = false;
	if (parentReferrer.type != UserManager.TYPE_CREDITOR) {
		for (var i = 0; i < parentReferrer.children.length && !foundAndDeleted; i++) {
			if (parentReferrer.children[i].id == referrerId) {
				parentReferrer.children.splice(i, 1);
				return true;
			} else if (parentReferrer.children[i].type != UserManager.TYPE_CREDITOR) {
				foundAndDeleted = UserManager.deleteReferrer(referrerId, parentReferrer.children[i]);
			}
		}
	}
	return foundAndDeleted;
};

/**
 * Compares two roles
 */
UserManager.compareRoles = function(role1, role2) {
	return role1.name.compare(role2.name);
};
